/**
 * 地图上的点位编辑器.
 * 属性:
 * + editable(编辑模式,否则为展示模式)
 * + maxLevel(最多展示层级,默认为1级,如果层级多,则叠加展示,一般在展示模式会用多层级)
 * + dbPositionMap(点位集合,都是已经在数据库中创建过的节点)
 * + parent(当前编辑节点所在父节点内容,如果为null或undefined表示在根节点,即地球上编辑子节点)
 * + value(即current,当前编辑节点内容,可能是已经在数据库中创建过的节点,也可能是正准备要创建的节点)
 * + onChange(改变了当前节点的属性,更新到current中)
 * 
 * 添加逻辑:
 * + 点,point
 *  - 点击按钮切换到创建状态, 点击地图释放后创建成功, 点击释放后就取消创建状态.
 * + 圆,circle
 *  - 点击按钮切换到创建圆状态, 第一次点击选定圆心, 移动鼠标时改变圆半径, 再次点击后确定圆半径, 并完成创建状态.
 * + 长方形,rectangle
 *  - 同圆, 支持两种模式, 按住并拖动和点击移动二次点击.
 * + 多边形,polygon
 * 
 * 编辑逻辑:
 * + 一般情况下只有一个点位处于编辑模式.
 * + 编辑时,点击背景图,则背景图处于上层,点击图形,则图形处于上层.
 * 
 * 展示逻辑:
 * + 展示时,背景图处于下层,形状处于上层.
 * 
 * 参考:
 * 1. 添加移动删除Markers<https://tomickigrzegorz.github.io/react-leaflet-examples/#/add-move-and-delete-marker>
 */
import * as React from 'react';
import {
  Marker,
  // Popup,
  Circle,
  Rectangle,
  Polygon,
  CircleMarker,
  useMapEvents,
} from "react-leaflet";
import L, { LatLngTuple } from "leaflet";
import { PositionMode, PositionType, SupportAreaTypes } from "../types";
import { ReactDistortableImageOverlay, calculateTransform, getMatrixString } from "./ReactDistortableImageOverlay";

const fillBlueOptions = { fillColor: 'blue' }

const EditIcon = L.divIcon({
  html: `
  <svg height="24" width="24">
    <circle cx="12" cy="12" r="10" stroke="yellow" stroke-width="3" stroke-dashArray='3,3' fill="none" />
  </svg> 
  `,
  className: "",
  iconSize: [24, 24],
  // iconAnchor: [12, 40],
});

const SvgGraph = ({ value }: { value: Partial<PositionType>, editing?: boolean }) => {
  const areaType = value.areaType;
  if (!areaType || !SupportAreaTypes.includes(areaType)) {
    console.log('not support areaType=', areaType);
    return null;
  }
  if (areaType === 'point') {
    if (value.location)
      return (
        <CircleMarker center={value.location} pathOptions={fillBlueOptions} radius={5} />
      )
    else
      return null;
  } else if (areaType === 'circle') {
    const radius = value.area as number;
    if (value.location && !isNaN(radius))
      return (
        <Circle center={value.location} pathOptions={fillBlueOptions} radius={radius || 0} />
      )
    else
      return null;
  } else if (areaType === 'rectangle') {
    if (value.location && value.area) {
      const rect = [value.location, value.area];
      return (
        <Rectangle bounds={rect} pathOptions={fillBlueOptions} />
      )
    } else {
      return null;
    }
  } else if (areaType === 'polygon') {
    if (value.location) {
      // area为点列表,不包含第一个点,第一个点为location.
      let polygon = [value.location, ...(value.area as number[][] || [])];
      if (value._tmpArea) polygon.push(value._tmpArea)
      return (
        <Polygon pathOptions={fillBlueOptions} positions={polygon} />
      )
    } else
      return null;
  }
}

const SvgGraphEdit = ({ value, onChange }: { value: Partial<PositionType>, onChange?: (value: Partial<PositionType>) => void; }) => {
  const areaType = value.areaType;
  // const pointEventHandlers = {
  //   moveend(e: any) {
  //     // 移动点.
  //     const { lat, lng } = e.target.getLatLng();
  //     console.log('moveend', lat, lng);
  //     onChange?.({ ...(value || {}), location: [lat, lng] });
  //     return;
  //   }
  // }
  const eventHandlersLocation = {
    move(e: any) {
      // 移动点.
      const { lat, lng } = e.target.getLatLng();
      console.log('move', lat, lng, e);
      onChange?.({ ...(value || {}), location: [lat, lng] });
      return;
    }
  }
  const eventHandlersRectangleArea = {
    move(e: any) {
      // 移动点.
      const { lat, lng } = e.target.getLatLng();
      console.log('move', lat, lng, e);
      onChange?.({ ...(value || {}), area: [lat, lng] });
      return;
    }
  }
  function eventHandlersPolygonArea(pointIndex: number) {
    return {
      move(e: any) {
        // 移动点.
        const { lat, lng } = e.target.getLatLng();
        console.log('move', lat, lng, e);
        const nArea = [...(value.area as number[][] || [])];
        nArea.splice(pointIndex, 1, [lat, lng]);
        onChange?.({ ...(value || {}), area: nArea });
        return;
      }
    }
  }


  if (!areaType || !SupportAreaTypes.includes(areaType)) {
    console.log('not support areaType=', areaType);
    return null;
  }

  return (
  <>
    {value?.location ? <Marker icon={EditIcon} position={value.location} draggable={true} eventHandlers={eventHandlersLocation} /> : null}
    {(areaType === 'rectangle' && value?.area) ? (
      <Marker icon={EditIcon} position={value.area as LatLngTuple} draggable={true} eventHandlers={eventHandlersRectangleArea} />
    ):null}
    {(areaType === 'polygon' && value?.area) ? (
      (value.area as number[][])?.map((item: any, index: number) => (
        <Marker icon={EditIcon} key={index} position={item} draggable={true} eventHandlers={eventHandlersPolygonArea(index)} />
      ))
    ):null}
  </>
  )
}

interface OnePositionProps {
  value: Partial<PositionType>;
  onChange?: (value: Partial<PositionType>) => void;
  editing?: boolean; //处于编辑模式(一般情况下只有一个节点处于编辑模式)
}
const OnePosition = ({ value, onChange, editing = false }: OnePositionProps) => {
  // 展示一个节点.
  const imgRef = React.useRef<any>(undefined);
  const areaType = value?.areaType;
  // 模式:空表示展示模式,create表示创建模式,edit表示编辑模式,image表示编辑背景图片模式.
  const [mode, setMode] = React.useState<PositionMode>('view'); // location 不存在时为创建模式.
  React.useEffect(() => {
    // 切换点位时,重新设置mode.
    if (editing) {
      if (!value.location)
        setMode('create');
      else
        setMode('edit');
    } else {
      setMode('view');
    }
  }, [value.id, value.areaType]);
  const map = useMapEvents({
    click(e) {
      const { lat, lng } = e.latlng;
      console.log('click', lat, lng);
      if (editing && mode === 'create') {
        // 创建图形模式.
        if (areaType === 'point') {
          // 区域类型: 点,即Marker
          const nValue = { ...(value || {}), location: [lat, lng] }
          onChange?.(nValue);
          return;
        } else if (areaType === 'circle') {
          // 区域类型: 圆形
          if (!value?.location) {
            // 未设置圆心,首先设置圆心
            const nValue = { ...(value || {}), location: [lat, lng] }
            onChange?.(nValue);
            return;
          }
          const circleCenter = value?.location;
          const radius = map.distance(circleCenter, [lat, lng]);
          if (isNaN(radius) || radius <= 0) {
            // 松手时无半径,认为当前位置为圆心.
            console.log('松手时无半径,认为当前位置为圆心.', radius);
            const nValue = { ...(value || {}), location: [lat, lng] }
            onChange?.(nValue);
            return;
          }
          // 结束圆:松手时有半径,认为画圆结束.
          const nValue = { ...(value || {}), area: radius }
          onChange?.(nValue);
          setMode('view');
          return;
        } else if (areaType === 'rectangle') {
          // 区域类型: 矩形
          if (!value?.location) {
            // 第一个点未设置,先设置第一个点.
            const nValue = { ...(value || {}), location: [lat, lng] }
            onChange?.(nValue);
            return;
          }
          // 结束: 第二个点点击了.
          const nValue = { ...(value || {}), area: [lat, lng] };
          onChange?.(nValue);
          setMode('view');
          return;
        } else if (areaType === 'polygon') {
          // 区域类型: 多边形
          if (!value?.location) {
            // 第一个点未设置,先设置第一个点.
            const nValue = { ...(value || {}), location: [lat, lng] }
            onChange?.(nValue);
            return;
          }
          // 至少要大于等于3个点.
          if ((value?.area as number[][])?.length >= 2) {
            const lastPixel = map.project([lat, lng]);
            const firstPixel = map.project(value.location);
            const distancePixel = lastPixel.distanceTo(firstPixel);
            if (distancePixel < 10) {
              // 结束多边形:与第一点的距离小于10像素,认为是最后一点.
              const nValue = { ...(value || {}), _tmpArea: undefined };
              onChange?.(nValue);
              setMode('view');
              return;
            }
          }
          // 未结束,增加点.
          const nArea = [...(value?.area as number[][] || []), [lat, lng]];
          const nValue = { ...(value || {}), area: nArea };
          onChange?.(nValue);
          return;
        }
      }
      // map.locate()
    },
    // mousedown(e) {
    //   if (editing && mode === 'create') {
    //     // 创建图形模式.(按住模式)
    //     const { lat, lng } = e.latlng;
    //     console.log('mousedown', lat, lng);
    //     if (areaType === 'circle') {
    //       // 区域类型: 圆,按下鼠标时设置圆心(即location的值).
    //       // 注意: 未设置圆心时,才设置圆心. 若已设置圆心,鼠标松开表示圆半径确定.
    //       if (!value?.location) {
    //         const nValue = { ...(value || {}), location: [lat, lng] }
    //         onChange?.(nValue);
    //         return;
    //       }
    //     } else if(areaType === 'rectangle') {
    //       // 区域类型: 矩形,按下鼠标时设置第一个点(即location的值).
    //       // 注意: 第一个点未设置时,才设置. 若已设置第一点,鼠标松开时位置为第二点的位置.
    //       if (!value?.location) {
    //         const nValue = { ...(value || {}), location: [lat, lng] }
    //         onChange?.(nValue);
    //         return;
    //       }
    //     }
    //   }
    // },
    mousemove(e) {
      if (editing && mode === 'create') {
        // 创建图形模式.
        const { lat, lng } = e.latlng;
        // console.log('mousemove', lat, lng);
        if (areaType === 'circle') {
          if (value?.location) {
            // 已设置过圆心才需要展示圆,否则先设置圆心.
            const radius = map.distance(value.location, [lat, lng]);
            const nValue = { ...(value || {}), area: radius }
            onChange?.(nValue);
            return;
          }
        } else if (areaType === 'rectangle') {
          if (value?.location) {
            // 已设置过一点,再设置一点.
            const nValue = { ...(value || {}), area: [lat, lng] }
            onChange?.(nValue);
            return;
          }
        } else if (areaType === 'polygon') {
          if (value?.location) {
            // 已设置过起点,再设置最后一点.
            const nValue = { ...(value || {}), _tmpArea: [lat, lng] }
            onChange?.(nValue);
            return;
          }
        }
      }
    },
    // mouseup(e) {
    //   if (editing && mode === 'create') {
    //     // 创建图形模式.
    //     const { lat, lng } = e.latlng;
    //     console.log('mouseup', lat, lng);
    //     if (areaType === 'circle') {
    //       // 区域类型: 圆,松开鼠标时判断当前位置是否为圆心位置,如果是则表示点击了圆心,否则表示圆画完了.
    //       if (!value?.location) {
    //         // 未设置圆心,首先设置圆心
    //         const nValue = { ...(value || {}), location: [lat, lng] }
    //         onChange?.(nValue);
    //         return;
    //       }
    //       const circleCenter = value?.location;
    //       const radius = map.distance(circleCenter, [lat, lng]);
    //       if (isNaN(radius) || radius <= 0) {
    //         // 松手时无半径,认为当前位置为圆心.
    //         console.log('松手时无半径,认为当前位置为圆心.', radius);
    //         const nValue = { ...(value || {}), location: [lat, lng] }
    //         onChange?.(nValue);
    //         return;
    //       }
    //       // 结束圆:松手时有半径,认为画圆结束.
    //       const nValue = { ...(value || {}), area: radius }
    //       onChange?.(nValue);
    //       setMode('view');
    //       return;
    //     } else if (areaType === 'rectangle') {
    //       // 区域类型: 矩形.
    //       if (!value?.location) {
    //         // 未设置第一点,先设置第一点.
    //         const nValue = { ...(value || {}), location: [lat, lng] }
    //         onChange?.(nValue);
    //         return;
    //       }
    //       // 结束矩形:已经设置了第一点,再设置第二点
    //       const nValue = { ...(value || {}), area: [lat, lng] }
    //       onChange?.(nValue);
    //       setMode('view');
    //       return;
    //     }
    //   }
    // },
    // dragstart(e) {
    //   L.DomEvent.stopPropagation(e);
    //   L.DomEvent.preventDefault(e);
    //   // e.originalEvent.preventDefault();
    //   // e.originalEvent.stopPropagation();
    //   console.log('dragstart');
    // },
    // drag(e) {
    //   console.log('drag');
    // },
    // dragend(e) {
    //   L.DomEvent.preventDefault(e);
    //   L.DomEvent.stopPropagation(e);
    //   console.log('dragend');
    // },
    // locationfound(e) {
    //   setPosition(e.latlng)
    //   map.flyTo(e.latlng, map.getZoom())
    // },
  })

  function handleChangeCorners(evt: any) {
    console.log('evt', evt.type, evt.target._corners, evt);
    const corners = evt.target._corners;
    if (corners) {
      const _map = evt.target._map;
      const points = corners.map(_map.latLngToLayerPoint.bind(_map));
      const w = imgRef.current?.getElement()?.offsetWidth || 500;
      const h = imgRef.current?.getElement()?.offsetHeight || 375;
      const matrix = calculateTransform(points, w, h);
      const matrixString = getMatrixString(matrix);
      const nCorners = corners?.map((item: L.LatLng) => [item.lat, item.lng]);
      const bg = { ...(value.bg || {}), corners: nCorners, matrix, matrixString };
      console.log('onChange', bg);
      onChange?.({ ...(value || {}), bg });
    }
  }
  const bgEventHandlers = {
    // load: handleChangeCorners,
    update: handleChangeCorners,
    // edit: handleChangeCorners,
    // dragend: handleChangeCorners
  }

  const corners = value.bg?.corners;
  const corners1 = corners?.map((item: number[]) => L.latLng(item[0], item[1]));
  if (editing) console.log(mode);

  return (
    <>
      {value.bg?.image ? <ReactDistortableImageOverlay ref={imgRef} url={value.bg?.image} eventHandlers={bgEventHandlers} editing={editing} selected={editing} corners={corners1} /> : null}
      <SvgGraph value={value} />
      {editing ? <SvgGraphEdit value={value} onChange={onChange} /> : null}
    </>
  )
}

export default OnePosition;
